/*
	This file is part of PropExtractor.

	PropExtractor is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	PropExtractor is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with PropExtractor. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _PEARCHIVE_H_
#define _PEARCHIVE_H_

#include "PEFile.h"
#include "PEObject.h"

namespace pe
{

	enum ArchiveType
	{
		eArchiveType_AliceRed,
		eArchiveType_AliceAfa,
		eArchiveType_AliceAld
	};

	struct PEArchiveEntryRaw;

	struct PEArchiveDirRaw
	{
		char* name;

		PEArchiveDirRaw* subfolders;
		unsigned int subfolders_count;

		PEArchiveEntryRaw* children;
		unsigned int children_count;
	};

	struct PEArchiveEntryRaw
	{
		PEArchiveDirRaw* dir;

		wchar_t* path;
		wchar_t* filename;

		unsigned int offset;
		unsigned int filesize;
	};

	struct PEArchiveRaw
	{
		void* original;
		ArchiveType original_type;

		PEStream* handle;

		PEArchiveEntryRaw* entries;
		unsigned int entries_total;

		wchar_t* path;
		wchar_t* workingdir;
	};

	PE_EXPORT int PEArchiveRawGetEntry(PEArchiveEntryRaw** a_Target, PEArchiveRaw* a_Archive, unsigned int a_Index);
	PE_EXPORT int PEArchiveRawOpenFile(PEStream* a_Target, PEArchiveRaw* a_Archive, PEArchiveEntryRaw* a_Entry);
	PE_EXPORT int PEArchiveRawSaveCompressedFile(PEArchiveRaw* a_Archive, PEArchiveEntryRaw* a_Entry, const wchar_t* a_WorkingDir = NULL, const char* a_Pattern = "%workingdir%%name%%ext%");

	class PEArchive;
	class PEArchiveDirectory;
	class PEPath;

	class PE_DLL_EXPORT PEArchiveEntry
	{

		friend class PEArchive;

	public:

		PEArchiveEntry();
		~PEArchiveEntry();

		const wchar_t* GetLocalPath() { return m_LocalPath; }
		const wchar_t* GetFileName() { return m_FileName; }

		unsigned int GetOffset() { return m_Offset; }
		unsigned int GetFileSize() { return m_FileSize; }

		virtual int GetStreamShared(PEStream* a_Target) = 0;
		virtual PEStream* GetStream() = 0;

		int SaveCompressedToFile(const wchar_t* a_Path);

	protected:

		wchar_t* m_LocalPath;
		wchar_t* m_FileName;

		PEArchive* m_Parent;
		PEArchiveDirectory* m_Directory;

		unsigned int m_Offset;
		unsigned int m_FileSize;

	};
	
	class PE_DLL_EXPORT PEArchiveDirectory
	{

		friend class PEArchiveDirectory;

	public:

		PEArchiveDirectory(const wchar_t* a_Name);
		~PEArchiveDirectory();

		PEArchiveDirectory* FindChild(const wchar_t* a_Name, unsigned int a_TargetLevel, unsigned int a_CurrentLevel);

		PEArchiveDirectory* AddChild(PEPath* a_Path, unsigned int a_Level);
		void AddSibling(PEPath* a_Path, unsigned int a_Level);

	protected:

		wchar_t* m_Name;
		unsigned int m_Level;
		PEArchiveDirectory* m_Child;
		PEArchiveDirectory* m_Sibling;

	};

	class PE_DLL_EXPORT PEArchive : public PEObject
	{

	public:

		PEArchive();
		~PEArchive();

		const wchar_t* GetFilePath() { return m_Path; }
		virtual int LoadHeader(PEStream* a_Stream) = 0;
		virtual int LoadBody() = 0;

		unsigned int GetEntryTotal() { return m_ChildrenCount; }

		PEArchiveEntry* GetEntryByFileName(const wchar_t* a_Name);

		PEArchiveEntry* GetEntry(unsigned int a_Index);
		PEStream* GetEntryStream(unsigned int a_Index);

		int SetEntries(unsigned int a_Total);
		int AddEntry(const wchar_t* a_Path, unsigned int a_Offset);

	protected:

		void SetStream(PEStream* a_Stream);

		wchar_t* m_Path;
		wchar_t* m_Name;
		wchar_t* m_WorkingDir;

		PEStream* m_Shared;

		PEArchiveDirectory* m_DirectoryRoot;
		PEArchiveDirectory* m_Directories;
		unsigned int m_DirectoriesCount;

		PEArchive* m_SubArchives;
		unsigned int m_SubArchivesCount;

		PEArchiveEntry* m_Children;
		unsigned int m_ChildrenFilled;
		unsigned int m_ChildrenCount;

	};

}; // namespace pe

#endif